﻿using System;
using System.Collections.Generic;
using SweeperPrototype.Business.Fields;
using SweeperPrototype.Business.Keys;

namespace SweeperPrototype.Objects
{
    public class EffectiveExposureProvider : NotifyList<EffectiveExposure>
    {
        private readonly PositionProvider m_PositionProvider;
        private readonly ExposureMapProvider m_ExposureMapProvider;
        private readonly Dictionary<PositionSubscription.UniqueKey, NotifyList<EffectiveExposure>> m_EffectiveLookup;
        private readonly Dictionary<EffectiveExposure.UniqueKey, EffectiveExposure> m_ExactLookup;
        public EffectiveExposureProvider( PositionProvider position_provider,
                                          ExposureMapProvider map_provider )
        {

            m_PositionProvider = position_provider;
            m_ExposureMapProvider = map_provider;

            m_ExactLookup = new Dictionary<EffectiveExposure.UniqueKey, EffectiveExposure>();
            m_EffectiveLookup = new Dictionary<PositionSubscription.UniqueKey, NotifyList<EffectiveExposure>>();

            foreach( PositionSubscription sub in m_PositionProvider.Items )
            {
                OnPositionAdd( sub, -1 );
            }

            m_PositionProvider.Addition += OnPositionAdd;
            m_PositionProvider.Removal += OnPositionRemove;

            m_ExposureMapProvider.Addition += OnMapAdd;
            m_ExposureMapProvider.Removal += OnMapRemove;


        }
        

        public bool TryGet( PositionSubscription.UniqueKey pos_key, out NotifyList<EffectiveExposure> list )
        {
            return m_EffectiveLookup.TryGetValue(pos_key, out list); 
        }
        

        #region IMPLEMENTATION


        private void OnPositionAdd(PositionSubscription addition, int index)
        {
                // NOTE: this will fire addition event!
                INotifyList<ExposureMappingSubscription> mappings = m_ExposureMapProvider.Subscribe(addition.RIC);

                PositionSubscription.UniqueKey pos_key = new PositionSubscription.UniqueKey(addition.BookCode, addition.RIC);

                NotifyList<EffectiveExposure> eff_ex_list;
                if( m_EffectiveLookup.TryGetValue( pos_key, out eff_ex_list ) == false )
                {
                    eff_ex_list = new NotifyList<EffectiveExposure>();
                    m_EffectiveLookup.Add( pos_key, eff_ex_list );
                }
                else
                {
                    throw new Exception("I'm confused on app logic - or i've added a way to generate rows for positions which do not exist");
                }

                foreach( ExposureMappingSubscription map in mappings )
                {
                    EffectiveExposure eff_ex = new EffectiveExposure( addition, map );
                    m_ExactLookup.Add(new EffectiveExposure.UniqueKey(eff_ex), eff_ex);
                    eff_ex_list.Add( eff_ex );
                    Add( eff_ex );
                }
        }

        private void OnPositionRemove(PositionSubscription removal, int index)
        {
            PositionSubscription.UniqueKey pos_key = new PositionSubscription.UniqueKey(removal.BookCode, removal.RIC);
            NotifyList<EffectiveExposure> eff_ex_list;

            if (m_EffectiveLookup.TryGetValue(pos_key, out eff_ex_list) )
            {
                m_EffectiveLookup.Add(pos_key, eff_ex_list);
            }
            else
            {
                throw new Exception("I'm confused on app logic - or assumption on program flow no longer valid");
            }

            throw new Exception("Need to define policy in terms of what a removal means here");
        }

        private void OnMapRemove(ExposureMappingSubscription removal, int index)
        {
            throw new Exception("Need to define policy in terms of what a removal means here - is removal set exposure to zero - or is it a real remove?");
        }

        // get a listing of all relevant exposure mappings
        private void OnMapAdd(ExposureMappingSubscription addition, int index)
        {
            

                ExposureRIC exposure_ric = addition.ExposureRIC;

                foreach( PositionSubscription.UniqueKey pos_key in m_EffectiveLookup.Keys )
                {
                    if( pos_key.RIC == exposure_ric )
                    {
                        NotifyList<EffectiveExposure> list = m_EffectiveLookup[ pos_key ];
                        PositionSubscription pos = m_PositionProvider[ pos_key ];

                        // so a map is added, but in many cases we will already
                        // have an eff_ex defined, so we need to check for current existance.

                        EffectiveExposure eff_ex;
                        EffectiveExposure.UniqueKey key = new EffectiveExposure.UniqueKey(
                            pos.BookCode, addition.ExposureRIC, addition.EffectiveRIC
                            );

                        if (m_ExactLookup.TryGetValue(key, out eff_ex) == false )
                        {
                            eff_ex = new EffectiveExposure(pos, addition);
                            m_ExactLookup.Add(key, eff_ex);
                            list.Add(eff_ex);
                            Add(eff_ex);
                        }
                    
                    }
                }
        }
        
        #endregion

    }
}